package com.bestcem.xm.wallet.grpc.client;

import com.bestcem.bp.pay.grpc.v1.common.ListFinanceResponse;
import com.bestcem.bp.pay.grpc.v1.enums.FreezeTypeEnum;
import com.bestcem.bp.pay.grpc.v1.services.*;
import com.bestcem.xm.common.core.constant.GrpcClientNames;
import com.bestcem.xm.common.core.domain.web.ServiceResult;
import com.bestcem.xm.common.core.sign.grpc.core.GrpcTemplate;
import com.bestcem.xm.wallet.controller.vo.response.WalletFreezeInfoVO;
import com.bestcem.xm.wallet.grpc.client.converter.WalletGrpcConvert;
import com.bestcem.xm.wallet.grpc.client.converter.WalletWalletConverter;
import com.bestcem.xm.wallet.grpc.client.dto.*;
import com.bestcem.xm.wallet.grpc.client.param.RechargeMiniProgramParam;
import com.bestcem.xm.wallet.service.dto.WalletRechargeInfoDTO;
import com.zy.dp.proto.base.v1.Code;
import lombok.extern.slf4j.Slf4j;
import net.devh.boot.grpc.client.inject.GrpcClient;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 企业钱包相关grpc接口
 *
 * @author qiongyu.cui <qiongyu.cui@idiaoyan.com>
 * @version v1.0
 * @date 2022/5/11 13:16
 */
@Slf4j
@Service(value = "walletWalletGrpcService")
public class WalletWalletGrpcService {
    @GrpcClient(GrpcClientNames.PAY)
    private WalletServiceGrpc.WalletServiceBlockingStub stub;
    @Resource
    private GrpcTemplate grpcTemplate;
    @Resource
    private WalletGrpcConvert walletGrpcConvert;

    /**
     * 分页查询钱包交易明细记录
     *
     * @param page     第几页
     * @param size     每页大小
     * @param walletId 钱包id
     * @param type     交易类型
     * @return com.bestcem.bp.pay.grpc.v1.common.ListFinanceResponse
     * @author cuiqiongyu <qiongyu.cui@idiaoyan.cn>
     * @date 2022/03/18 16:07
     */
    public ListFinanceDTO listFinanceRecords(Integer page, Integer size, String walletId, Integer type) {
        page = (Objects.isNull(page) || page <= 0) ? 1 : page;
        size = (Objects.isNull(size) || size <= 0) ? 10 : size;
        if (log.isInfoEnabled()) {
            log.info("分页查询钱包交易明细记录参数：page:{} size:{} walletId:{} type:{}", page, size, walletId, type);
        }

        ListFinanceRecordsRequest.Builder builder = ListFinanceRecordsRequest.newBuilder();
        builder.setPage(page);
        builder.setSize(size);
        builder.setWalletId(walletId);
        if (Objects.nonNull(type)) {
            builder.setTypeValue(type);
        }

        ListFinanceRecordsRequest request = builder.build();
        // 加签并请求
        grpcTemplate.addSign(request, GrpcTemplate.SEVER_CODE_PAY);
        ListFinanceResponse listFinanceResponse = stub.listFinanceRecords(request);
        // 校验查询结果
        if (Code.ERROR_VALUE == listFinanceResponse.getStatus().getCodeValue()) {
            log.error("分页查询钱包交易明细记录失败：dto:{} page:{} size:{} walletId:{} type:{}", listFinanceResponse.getStatus().getMessage(),
                    page, size, walletId, type);
            return null;
        }

        return WalletWalletConverter.responseToListFinanceDTO(listFinanceResponse);
    }

    /**
     * 获取钱包
     *
     * @param id 钱包id
     * @return com.bestcem.bp.pay.grpc.v1.services.GetWalletResponse
     * @author panyun <yun.pan@idiaoyan.com>
     * @date 2022/3/18 17:45
     */
    public WalletInfoDTO getWallet(String id) {
        if (log.isInfoEnabled()) {
            log.info("获取钱包 id:{} ", id);
        }
        // 加签并请求
        GetWalletRequest request = GetWalletRequest.newBuilder().setId(id).build();
        grpcTemplate.addSign(request, GrpcTemplate.SEVER_CODE_PAY);
        GetWalletResponse response = stub.getWallet(request);

        // 校验查询结果
        if (Code.ERROR_VALUE == response.getStatus().getCodeValue()) {
            log.error("获取钱包失败 id:{}", id);
            return null;
        }
        return WalletWalletConverter.responseToWalletInfoDto(response);
    }

    /**
     * 获取钱包占用金额
     *
     * @param walletId    钱包id
     * @param freezeTypes 冻结类型列表
     * @return java.lang.Integer
     * @author panyun <yun.pan@idiaoyan.com>
     * @date 2022/3/20 19:08
     */
    public List<WalletFreezeInfoVO> getWalletFreeze(String walletId, List<Integer> freezeTypes) {
        if (log.isInfoEnabled()) {
            log.info("获取钱包占用金额 id:{} ", walletId);
        }

        // 本地冻结类型转为grpc实体类型
        List<FreezeTypeEnum.FreezeType> types = freezeTypes.stream()
                .map(FreezeTypeEnum.FreezeType::forNumber)
                .collect(Collectors.toList());

        GetWalletFreezeRequest.Builder builder = GetWalletFreezeRequest.newBuilder()
                .setWalletId(walletId)
                .addAllFreezeTypes(types);
        // 加签并请求
        GetWalletFreezeRequest request = builder.build();
        grpcTemplate.addSign(request, GrpcTemplate.SEVER_CODE_PAY);
        GetWalletFreezeResponse response = stub.getWalletFreeze(request);

        // 校验查询结果
        if (Code.ERROR_VALUE == response.getStatus().getCodeValue()) {
            log.error("获取钱包占用金额失败 id:{}", walletId);
            return Collections.emptyList();
        }
        ArrayList<WalletFreezeInfoVO> list = new ArrayList<>();
        for (WalletFreezeInfo freezeInfo : response.getFreezesList()) {
            WalletFreezeInfoVO vo = new WalletFreezeInfoVO();
            vo.setFreezeType(freezeInfo.getFreezeTypeValue())
                    .setAmount(BigDecimal.valueOf(freezeInfo.getAmount()).movePointLeft(2));
            list.add(vo);
        }
        return list;
    }

    /**
     * 余额充值
     *
     * @param platformCode 平台代码
     * @param walletId     钱包id
     * @param rechargeDTO  充值参数
     * @param financeDTO   交易参数
     * @return com.bestcem.xm.wallet.service.dto.WalletRechargeInfoDTO
     * @author panyun <yun.pan@idiaoyan.com>
     * @date 2022/3/20 22:12
     */
    public WalletRechargeInfoDTO rechargeWallet(String platformCode, String walletId, WalletRechargeDTO rechargeDTO, WalletFinanceDTO financeDTO) {
        // 设置参数
        RechargeWalletRequest request = RechargeWalletRequest.newBuilder()
                .setPlatformCode(platformCode)
                .setWalletId(walletId)
                .setRechargeArgs(walletGrpcConvert.dto2RechargeArgsGrpc(rechargeDTO))
                .setFinanceArgs(walletGrpcConvert.dto2FinanceArgsGrpc(financeDTO))
                .build();
        // 加签并请求
        grpcTemplate.addSign(request, GrpcTemplate.SEVER_CODE_PAY);
        RechargeWalletResponse response = null;
        try {
            response = stub.rechargeWallet(request);
        } catch (Exception e) {
            log.error("余额充值。请求失败", e);
        }
        // 返回值处理
        if (response != null && Code.OK_VALUE == response.getStatus().getCodeValue()) {
            return walletGrpcConvert.rechargeInfoGrpc2Dto(response.getRecharge());
        } else {
            log.error("余额充值。请求失败, response:{}", response != null ? response.toString() : null);
        }
        return null;
    }

    /**
     * 获取充值订单
     *
     * @param orderId 订单id
     * @return com.bestcem.xm.wallet.grpc.client.dto.RechargeInfoDTO
     * @author panyun <yun.pan@idiaoyan.com>
     * @date 2022/3/20 23:35
     */
    public RechargeInfoDTO getRechargeOrder(String orderId) {
        if (log.isInfoEnabled()) {
            log.info("获取充值订单 id:{} ", orderId);
        }
        // 加签并请求
        GetRechargeOrderRequest request = GetRechargeOrderRequest.newBuilder().setId(orderId).build();
        grpcTemplate.addSign(request, GrpcTemplate.SEVER_CODE_PAY);

        // 请求
        GetRechargeOrderResponse response = null;
        try {
            response = stub.getRechargeOrder(request);
        } catch (Exception e) {
            log.error("获取充值订单。请求失败", e);
        }

        // 返回值处理
        if (response != null && Code.OK_VALUE == response.getStatus().getCodeValue()) {
            if (log.isInfoEnabled()) {
                log.info("获取充值订单。response:{}", response.toString());
            }
            return WalletWalletConverter.responseToRechargeInfoDto(response);
        } else {
            log.error("获取充值订单。请求失败, response:{}", response != null ? response.toString() : null);
        }
        return null;
    }

    /**
     * 小程序预充值
     *
     * @param param 请求参数
     * @return 小程序唤起支付参数
     */
    public ServiceResult<RechargeMiniProgramDTO> rechargeMiniProgram(RechargeMiniProgramParam param) {
        RechargeMiniProgramRequest request = walletGrpcConvert.rechargeMiniProgramParam2Grpc(param);
        RechargeMiniProgramResponse response;
        try {
            grpcTemplate.addSign(request, GrpcTemplate.SEVER_CODE_PAY);
            response = stub.rechargeMiniProgram(request);
        } catch (Exception e) {
            log.error("【企业钱包】小程序充值参数失败：", e);
            return ServiceResult.fail("");
        }

        // 返回值处理
        if (response == null || Code.OK_VALUE != response.getStatus().getCodeValue()) {
            log.error("【企业钱包】小程序充值参数失败：, response:{}", response != null ? response.toString() : null);
            return ServiceResult.fail("");
        }

        RechargeMiniProgramDTO rechargeMiniProgramDTO = this.convert(response);

        return ServiceResult.success(rechargeMiniProgramDTO);
    }

    private RechargeMiniProgramDTO convert(RechargeMiniProgramResponse param) {
        RechargeMiniProgramDTO res = new RechargeMiniProgramDTO();
        res.setOrderId(param.getOrderId());

        RechargeMiniProgramArgs rechargeMiniProgramArgs = param.getMiniProgramArgs();
        res.setAppId(rechargeMiniProgramArgs.getAppId());
        res.setTimestamp(rechargeMiniProgramArgs.getTimestamp());
        res.setNonceStr(rechargeMiniProgramArgs.getNonceStr());
        res.setDataPackage(rechargeMiniProgramArgs.getPackage());
        res.setSignType(rechargeMiniProgramArgs.getSignType());
        res.setPaySign(rechargeMiniProgramArgs.getPaySign());

        return res;
    }
}
